package com.nineclock.auth.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.nineclock.auth.entity.IntegrationAuthenticationEntity;
import com.nineclock.auth.processor.AuthenticationProcessor;
import com.nineclock.auth.threadlocal.IntegrationAuthenticationHolder;
import com.nineclock.auth.threadlocal.UserHolder;
import com.nineclock.common.entity.NcAuthority;
import com.nineclock.common.entity.UserInfo;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysRoleDTO;
import com.nineclock.system.dto.SysUserDTO;
import com.nineclock.system.feign.SysUserFeign;
import jdk.nashorn.internal.ir.annotations.Ignore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    //自动注入 所有的 认证处理器 到 集合中
    @Autowired
    List<AuthenticationProcessor> processors;

    @Autowired
    SysUserFeign userFeign;

    /**
     * 1. 根据用户名获取userDto
     * 2. 封装userDetails对象
     *
     * @param username
     * @return  返回userDetails对象
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //从线程中获取 认证的实体对象
        IntegrationAuthenticationEntity entity = IntegrationAuthenticationHolder.get();
        //根据认证实体获取 认证处理器
        AuthenticationProcessor processor = this.chooseAuthenticationProcessor(entity);
        //根据不同的认证处理器 获取 UserDTO对象
        SysUserDTO userDTO = processor.authenticate(entity);

        if(userDTO == null){
            throw new NcException(ResponseEnum.USER_NOT_FOUND);
        }
        //把userDTO转换为userInfo
        UserInfo userInfo = BeanHelper.copyProperties(userDTO, UserInfo.class);

        //获取客户端表示
        String clientId = entity.getAuthParameter("client_id");
        String companyId = entity.getAuthParameter("company_id");

        //设置客户端id
        userInfo.setClientId(clientId);
        //如果client_id 等于  pc_client，说明是pc端的登录， pc要求必须管理员才能登录
        //需要根据用户id， 企业id，查询员工信息，包含角色信息, 通过角色信息判断是否是管理员
        if("pc_client".equals(clientId)){
            List<SysCompanyUserDTO> companyUserDTOList;
            //如果企业id为null， 说明第一个点击登录
            if(StrUtil.isEmpty(companyId)){
                companyUserDTOList = userFeign.queryCompanyUser(null, userDTO.getId()).getData();
            }
            //如果企业id不为null， 说明第二次点击，点击进入企业
            else {
                companyUserDTOList = userFeign.queryCompanyUser(Long.valueOf(companyId), userDTO.getId()).getData();
            }

            //判断是否是管理员
            Boolean flag = checkCompanyUserIsAdmin(companyUserDTOList);
            if(! flag){
                throw new NcException(ResponseEnum.USER_NOT_COMPANY_ADMIN);
            }
            //对userInfo重新封装，把员工信息和企业信息封装进去
            wrapper(userInfo, companyUserDTOList);

        } else{
            //否则app登录
            //如果企业id为null， 获取最后一次登录使用的企业
            if(StrUtil.isEmpty(companyId)){
                companyId = userDTO.getLastLoginCompanyId() + "";
            }

            List<SysCompanyUserDTO> companyUserDTOList = userFeign.queryCompanyUser(Long.valueOf(companyId), userDTO.getId()).getData();

            wrapper(userInfo, companyUserDTOList);
        }


        //创建权限和角色 集合对象
        // List<GrantedAuthority> list = new ArrayList<>();
        // list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        List<GrantedAuthority> grantedAuthorities = userInfo.getGrantedAuthorities();


        //在当前线程存储 userInfo
        UserHolder.set(userInfo);
        //封装userDetails对象
        User user = new User(JsonUtils.toString(userInfo), userDTO.getPassword(), grantedAuthorities);

        return user;
    }

    private void wrapper(UserInfo userInfo, List<SysCompanyUserDTO> companyUserDTOList) {
        if(CollectionUtil.isEmpty(companyUserDTOList)){
            return;
        }
        SysCompanyUserDTO companyUserDTO = companyUserDTOList.get(0);

        userInfo.setCompanyId(companyUserDTO.getCompanyId());
        userInfo.setCompanyName(companyUserDTO.getCompanyName());
        userInfo.setCompanyUserId(companyUserDTO.getId());
        userInfo.setDepartmentId(companyUserDTO.getDepartmentId());
        userInfo.setDepartmentName(companyUserDTO.getDepartmentName());
        userInfo.setPost(companyUserDTO.getPost());
        userInfo.setWorkNumber(companyUserDTO.getWorkNumber());
        userInfo.setTimeEntry(companyUserDTO.getTimeEntry());
        userInfo.setEnable(true);
        List<NcAuthority> ncAuthorities = companyUserDTO.getGrantedAuthorities();
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(ncAuthorities)){
            grantedAuthorities.addAll(ncAuthorities);
            userInfo.setGrantedAuthorities(grantedAuthorities );
        }

    }

    /**
     * 判断 员工是否是管理员
     * @param companyUserDTOList
     * @return
     */
    private Boolean checkCompanyUserIsAdmin(List<SysCompanyUserDTO> companyUserDTOList) {
        if(CollectionUtil.isEmpty(companyUserDTOList)){
            return false;
        }

        for (SysCompanyUserDTO companyUserDTO : companyUserDTOList) {
            //获取角色列表
            List<SysRoleDTO> roles = companyUserDTO.getRoles();
            //循环角色列表
            if(CollectionUtil.isNotEmpty(roles)){
                for (SysRoleDTO role : roles) {
                    if(role.getRoleName() != null && role.getRoleName().startsWith("ROLE_ADMIN")){
                        return true;
                    }
                }
            }
        }
        return false;
    }


    public AuthenticationProcessor chooseAuthenticationProcessor(IntegrationAuthenticationEntity entity){
        if (processors != null && processors.size() > 0){
            for (AuthenticationProcessor processor : processors) {
                boolean flag = processor.support(entity);
                if(flag){
                    return processor;
                }
            }
        }
        return null;
    }
}